import $ from 'jquery';
import Button from './Button';
import Popover from '../Popover';

const slice = Array.prototype.slice;

class ImagePopover extends Popover {
    render() {
        let tpl;
        tpl = `<div class="link-settings">\n  <div class="settings-field">\n    <label>${this._t('imageUrl')}</label>\n    <input class="image-src" type="text" tabindex="1" />\n    <a class="btn-upload" href="javascript:;"\n      title="${this._t('uploadImage')}" tabindex="-1">\n      <span class="simditor-icon simditor-icon-upload"></span>\n    </a>\n  </div>\n  <div class='settings-field'>\n    <label>${this._t('imageAlt')}</label>\n    <input class="image-alt" id="image-alt" type="text" tabindex="1" />\n  </div>\n  <div class="settings-field">\n    <label>${this._t('imageSize')}</label>\n    <input class="image-size" id="image-width" type="text" tabindex="2" />\n    <span class="times">×</span>\n    <input class="image-size" id="image-height" type="text" tabindex="3" />\n    <a class="btn-restore" href="javascript:;"\n      title="${this._t('restoreImageSize')}" tabindex="-1">\n      <span class="simditor-icon simditor-icon-undo"></span>\n    </a>\n  </div>\n</div>`;
        this.el.addClass('image-popover').append(tpl);
        this.srcEl = this.el.find('.image-src');
        this.widthEl = this.el.find('#image-width');
        this.heightEl = this.el.find('#image-height');
        this.altEl = this.el.find('#image-alt');
        this.srcEl.on('keydown', ((_this => e => {
            let range;
            if (!(e.which === 13 && !_this.target.hasClass('uploading'))) {
                return;
            }
            e.preventDefault();
            range = document.createRange();
            _this.button.editor.selection.setRangeAfter(_this.target, range);
            return _this.hide();
        }))(this));
        this.srcEl.on('blur', ((_this => e => _this._loadImage(_this.srcEl.val())))(this));
        this.el.find('.image-size').on('blur', ((_this => e => {
            _this._resizeImg($(e.currentTarget));
            return _this.el.data('popover').refresh();
        }))(this));
        this.el.find('.image-size').on('keyup', ((_this => e => {
            let inputEl;
            inputEl = $(e.currentTarget);
            if (!(e.which === 13 || e.which === 27 || e.which === 9)) {
                return _this._resizeImg(inputEl, true);
            }
        }))(this));
        this.el.find('.image-size').on('keydown', ((_this => e => {
            let $img;
            let inputEl;
            let range;
            inputEl = $(e.currentTarget);
            if (e.which === 13 || e.which === 27) {
                e.preventDefault();
                if (e.which === 13) {
                    _this._resizeImg(inputEl);
                } else {
                    _this._restoreImg();
                }
                $img = _this.target;
                _this.hide();
                range = document.createRange();
                return _this.button.editor.selection.setRangeAfter($img, range);
            } else if (e.which === 9) {
                return _this.el.data('popover').refresh();
            }
        }))(this));
        this.altEl.on('keydown', ((_this => e => {
            let range;
            if (e.which === 13) {
                e.preventDefault();
                range = document.createRange();
                _this.button.editor.selection.setRangeAfter(_this.target, range);
                return _this.hide();
            }
        }))(this));
        this.altEl.on('keyup', ((_this => e => {
            if (e.which === 13 || e.which === 27 || e.which === 9) {
                return;
            }
            _this.alt = _this.altEl.val();
            return _this.target.attr('alt', _this.alt);
        }))(this));
        this.el.find('.btn-restore').on('click', ((_this => e => {
            _this._restoreImg();
            return _this.el.data('popover').refresh();
        }))(this));
        this.editor.on('valuechanged', ((_this => e => {
            if (_this.active) {
                return _this.refresh();
            }
        }))(this));
        return this._initUploader();
    }

    _initUploader() {
        let $uploadBtn;
        let createInput;
        $uploadBtn = this.el.find('.btn-upload');
        if (this.editor.uploader == null) {
            $uploadBtn.remove();
            return;
        }
        createInput = ((_this => () => {
            if (_this.input) {
                _this.input.remove();
            }
            return _this.input = $('<input/>', {
                type: 'file',
                title: _this._t('uploadImage'),
                multiple: true,
                accept: 'image/*'
            }).appendTo($uploadBtn);
        }))(this);
        createInput();
        this.el.on('click mousedown', 'input[type=file]', e => e.stopPropagation());
        return this.el.on('change', 'input[type=file]', ((_this => e => {
            _this.editor.uploader.upload(_this.input, {
                inline: true,
                img: _this.target
            });
            return createInput();
        }))(this));
    }

    _resizeImg(inputEl, onlySetVal) {
        let height;
        let value;
        let width;
        if (onlySetVal == null) {
            onlySetVal = false;
        }
        value = inputEl.val() * 1;
        if (!(this.target && ($.isNumeric(value) || value < 0))) {
            return;
        }
        if (inputEl.is(this.widthEl)) {
            width = value;
            height = this.height * value / this.width;
            this.heightEl.val(height);
        } else {
            height = value;
            width = this.width * value / this.height;
            this.widthEl.val(width);
        }
        if (!onlySetVal) {
            this.target.attr({
                width,
                height
            });
            return this.editor.trigger('valuechanged');
        }
    }

    _restoreImg() {
        let ref;
        let size;
        size = ((ref = this.target.data('image-size')) != null ? ref.split(",") : void 0) || [this.width, this.height];
        this.target.attr({
            width: size[0] * 1,
            height: size[1] * 1
        });
        this.widthEl.val(size[0]);
        this.heightEl.val(size[1]);
        return this.editor.trigger('valuechanged');
    }

    _loadImage(src, callback) {
        if (/^data:image/.test(src) && !this.editor.uploader) {
            if (callback) {
                callback(false);
            }
            return;
        }
        if (this.target.attr('src') === src) {
            return;
        }
        return this.button.loadImage(this.target, src, ((_this => img => {
            let blob;
            if (!img) {
                return;
            }
            if (_this.active) {
                _this.width = img.width;
                _this.height = img.height;
                _this.widthEl.val(_this.width);
                _this.heightEl.val(_this.height);
            }
            if (/^data:image/.test(src)) {
                blob = _this.editor.util.dataURLtoBlob(src);
                blob.name = "Base64 Image.png";
                _this.editor.uploader.upload(blob, {
                    inline: true,
                    img: _this.target
                });
            } else {
                _this.editor.trigger('valuechanged');
            }
            if (callback) {
                return callback(img);
            }
        }))(this));
    }

    show() {
        let $img;
        let args;
        args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
        super.show.apply(this, args);
        $img = this.target;
        this.width = $img.width();
        this.height = $img.height();
        this.alt = $img.attr('alt');
        if ($img.hasClass('uploading')) {
            return this.srcEl.val(this._t('uploading')).prop('disabled', true);
        } else {
            this.srcEl.val($img.attr('src')).prop('disabled', false);
            this.widthEl.val(this.width);
            this.heightEl.val(this.height);
            return this.altEl.val(this.alt);
        }
    }
}

ImagePopover.prototype.offset = {
    top: 6,
    left: -4
};

export default class ImageButton extends Button {
    _init() {
        this.editor = this.editor || this.opts.editor;
        this.title = this._t(this.name);
        let item, k, len, ref;
        if (this.editor.opts.imageButton) {
            if (Array.isArray(this.editor.opts.imageButton)) {
                this.menu = [];
                ref = this.editor.opts.imageButton;
                for (k = 0, len = ref.length; k < len; k++) {
                    item = ref[k];
                    this.menu.push({ name: `${item}-image`, text: this._t(`${item}Image`) });
                }
            } else {
                this.menu = false;
            }
        } else {
            if (this.editor.uploader != null) {
                this.menu = [
                    {
                        name: 'upload-image',
                        text: this._t('uploadImage')
                    }, {
                        name: 'external-image',
                        text: this._t('externalImage')
                    }
                ];
            } else {
                this.menu = false;
            }
        }
        this.defaultImage = this.editor.opts.defaultImage;
        this.editor.body.on('click', 'img:not([data-non-image])', ((_this => e => {
            let $img;
            let range;
            $img = $(e.currentTarget);
            range = document.createRange();
            range.selectNode($img[0]);
            _this.editor.selection.range(range);
            if (!_this.editor.util.support.onselectionchange) {
                _this.editor.trigger('selectionchanged');
            }
            return false;
        }))(this));
        this.editor.body.on('mouseup', 'img:not([data-non-image])', e => false);
        this.editor.on('selectionchanged.image', () => {
            let $contents, $img, range;
            range = this.editor.selection.range();
            if (range == null) return;
            $contents = $(range.cloneContents()).contents();
            if ($contents.length === 1 && $contents.is('img:not([data-non-image])')) {
                $img = $(range.startContainer).contents().eq(range.startOffset);
                return this.popover.show($img);
            } else {
                return this.popover.hide();
            }
        });
        this.editor.on('valuechanged.image', ((_this => () => {
            let $masks;
            $masks = _this.editor.wrapper.find('.simditor-image-loading');
            if (!($masks.length > 0)) {
                return;
            }
            return $masks.each((i, mask) => {
                let $img;
                let $mask;
                let file;
                $mask = $(mask);
                $img = $mask.data('img');
                if (!($img && $img.parent().length > 0)) {
                    $mask.remove();
                    if ($img) {
                        file = $img.data('file');
                        if (file) {
                            _this.editor.uploader.cancel(file);
                            if (_this.editor.body.find('img.uploading').length < 1) {
                                return _this.editor.uploader.trigger('uploadready', [file]);
                            }
                        }
                    }
                }
            });
        }))(this));
        return super._init(this);
    }
    render() {
        super.render();
        this.popover = new ImagePopover({ button: this });
        if (this.editor.opts.imageButton === 'upload') return this._initUploader(this.el);
    }
    renderMenu() {
        super.renderMenu.call(this);
        return this._initUploader();
    }
    _initUploader($uploadItem) {
        let $input;
        let createInput;
        let uploadProgress;
        if ($uploadItem == null) {
            $uploadItem = this.menuEl.find('.menu-item-upload-image');
        }
        if (this.editor.uploader == null) {
            this.el.find('.btn-upload').remove();
            return;
        }
        $input = null;
        createInput = ((_this => () => {
            if ($input) $input.remove();

            return $input = $('<input/>', {
                type: 'file',
                title: _this._t('uploadImage'),
                multiple: true,
                accept: 'image/*'
            }).appendTo($uploadItem);
        }))(this);
        createInput();
        $uploadItem.on('click mousedown', 'input[type=file]', e => {
            e.stopPropagation();
        });
        $uploadItem.on('change', 'input[type=file]', (e) => {
            if (this.editor.inputManager.focused) {
                this.editor.uploader.upload($input, {
                    inline: true
                });
                createInput();
            } else {
                this.editor.one('focus', (e) => {
                    this.editor.uploader.upload($input, {
                        inline: true
                    });
                    return createInput();
                });
                this.editor.focus();
            }
            return this.wrapper.removeClass('menu-on');
        });
        this.editor.uploader.on('beforeupload', ((_this => (e, file) => {
            let $img;
            if (!file.inline) return;
            if (file.img) {
                $img = $(file.img);
            } else {
                $img = _this.createImage(file.name);
                file.img = $img;
            }
            $img.addClass('uploading');
            $img.data('file', file);
            return _this.editor.uploader.readImageFile(file.obj, img => {
                let src;
                if (!$img.hasClass('uploading')) {
                    return;
                }
                src = img ? img.src : _this.defaultImage;
                return _this.loadImage($img, src, () => {
                    if (_this.popover.active) {
                        _this.popover.refresh();
                        return _this.popover.srcEl.val(_this._t('uploading')).prop('disabled', true);
                    }
                });
            });
        }))(this));
        uploadProgress = $.proxy(this.editor.util.throttle((e, file, loaded, total) => {
            let $img;
            let $mask;
            let percent;
            if (!file.inline) {
                return;
            }
            $mask = file.img.data('mask');
            if (!$mask) {
                return;
            }
            $img = $mask.data('img');
            if (!($img.hasClass('uploading') && $img.parent().length > 0)) {
                $mask.remove();
                return;
            }
            percent = loaded / total;
            percent = (percent * 100).toFixed(0);
            if (percent > 99) {
                percent = 99;
            }
            return $mask.find('.progress').height(`${100 - percent}%`);
        }, 500), this);
        this.editor.uploader.on('uploadprogress', uploadProgress);
        this.editor.uploader.on('uploadsuccess', ((_this => (e, file, result) => {
            let $img;
            let img_path;
            let msg;
            if (!file.inline) {
                return;
            }
            $img = file.img;
            if (!($img.hasClass('uploading') && $img.parent().length > 0)) {
                return;
            }
            if (typeof result !== 'object') {
                try {
                    result = $.parseJSON(result);
                } catch (_error) {
                    e = _error;
                    result = {
                        success: false
                    };
                }
            }
            if (result.success === false) {
                msg = result.msg || _this._t('uploadFailed');
                alert(msg);
                img_path = _this.defaultImage;
            } else {
                img_path = result.url;
            }
            _this.loadImage($img, img_path, () => {
                let $mask;
                $img.removeData('file');
                $img.removeClass('uploading').removeClass('loading');
                $mask = $img.data('mask');
                if ($mask) {
                    $mask.remove();
                }
                $img.removeData('mask');
                _this.editor.trigger('valuechanged');
                if (_this.editor.body.find('img.uploading').length < 1) {
                    return _this.editor.uploader.trigger('uploadready', [file, result]);
                }
            });
            if (_this.popover.active) {
                _this.popover.srcEl.prop('disabled', false);
                return _this.popover.srcEl.val(result.url);
            }
        }))(this));
        return this.editor.uploader.on('uploaderror', ((_this => (e, file, xhr) => {
            let $img;
            let msg;
            let result;
            if (!file.inline) {
                return;
            }
            if (xhr.statusText === 'abort') {
                return;
            }
            if (xhr.responseText) {
                try {
                    result = $.parseJSON(xhr.responseText);
                    msg = result.msg;
                } catch (_error) {
                    e = _error;
                    msg = _this._t('uploadError');
                }
                alert(msg);
            }
            $img = file.img;
            if (!($img.hasClass('uploading') && $img.parent().length > 0)) {
                return;
            }
            _this.loadImage($img, _this.defaultImage, () => {
                let $mask;
                $img.removeData('file');
                $img.removeClass('uploading').removeClass('loading');
                $mask = $img.data('mask');
                if ($mask) {
                    $mask.remove();
                }
                return $img.removeData('mask');
            });
            if (_this.popover.active) {
                _this.popover.srcEl.prop('disabled', false);
                _this.popover.srcEl.val(_this.defaultImage);
            }
            _this.editor.trigger('valuechanged');
            if (_this.editor.body.find('img.uploading').length < 1) {
                return _this.editor.uploader.trigger('uploadready', [file, result]);
            }
        }))(this));
    }
    _status() {
        return this._disableStatus();
    }
    loadImage($img, src, callback) {
        let $mask;
        let img;
        let positionMask;
        positionMask = ((_this => () => {
            let imgOffset;
            let wrapperOffset;
            imgOffset = $img.offset();
            wrapperOffset = _this.editor.wrapper.offset();
            return $mask.css({
                top: imgOffset.top - wrapperOffset.top,
                left: imgOffset.left - wrapperOffset.left,
                width: $img.width(),
                height: $img.height()
            }).show();
        }))(this);
        $img.addClass('loading');
        $mask = $img.data('mask');
        if (!$mask) {
            $mask = $('<div class="simditor-image-loading">\n  <div class="progress"></div>\n</div>').hide().appendTo(this.editor.wrapper);
            positionMask();
            $img.data('mask', $mask);
            $mask.data('img', $img);
        }
        img = new Image();
        img.onload = ((_this => () => {
            let height;
            let width;
            if (!$img.hasClass('loading') && !$img.hasClass('uploading')) {
                return;
            }
            width = img.width;
            height = img.height;
            $img.attr({
                src,
                width,
                height,
                'data-image-size': `${width},${height}`
            }).removeClass('loading');
            if ($img.hasClass('uploading')) {
                _this.editor.util.reflow(_this.editor.body);
                positionMask();
            } else {
                $mask.remove();
                $img.removeData('mask');
            }
            if ($.isFunction(callback)) {
                return callback(img);
            }
        }))(this);
        img.onerror = () => {
            if ($.isFunction(callback)) {
                callback(false);
            }
            $mask.remove();
            return $img.removeData('mask').removeClass('loading');
        };
        return img.src = src;
    }
    createImage(name) {
        let $img;
        let range;
        if (name == null) {
            name = 'Image';
        }
        if (!this.editor.inputManager.focused) {
            this.editor.focus();
        }
        range = this.editor.selection.range();
        range.deleteContents();
        this.editor.selection.range(range);
        $img = $('<img/>').attr('alt', name);
        range.insertNode($img[0]);
        this.editor.selection.setRangeAfter($img, range);
        this.editor.trigger('valuechanged');
        return $img;
    }
    command(src) {
        let $img;
        $img = this.createImage();
        return this.loadImage($img, src || this.defaultImage, ((_this => () => {
            _this.editor.trigger('valuechanged');
            _this.editor.util.reflow($img);
            $img.click();
            return _this.popover.one('popovershow', () => {
                _this.popover.srcEl.focus();
                return _this.popover.srcEl[0].select();
            });
        }))(this));
    }
}

ImageButton.prototype.name = 'image';
ImageButton.prototype.icon = 'picture-o';
ImageButton.prototype.htmlTag = 'img';
ImageButton.prototype.disableTag = 'pre, table';
ImageButton.prototype.defaultImage = '';
ImageButton.prototype.needFocus = false;